package modelado.problemas;

import java.util.List;

import modelado.datos.Datos;
import modelado.datos.DatosDiscretos;
import modelado.datos.elementos.Elemento;
import modelado.datos.elementos.ElementoConVariasInstancias;
import modelado.datos.elementos.Vertice;
import modelado.soluciones.Solucion;
import modelado.soluciones.SolucionConjunto;
import modelado.soluciones.SolucionLista;
import modelado.tipos.TipoDeObjetivo;
import modelado.tipos.TipoDeOptimizacion;
import modelado.tipos.TipoDeSolucion;

public abstract class ProblemaAbstracto implements Problema, GestionaProblema {
	private Datos datos;
	private DatosDiscretos datosDiscretos;
	private TipoDeObjetivo tipoDeObjetivo = TipoDeObjetivo.UNA_SOLUCION;
	private TipoDeOptimizacion tipoDeOptimizacion = TipoDeOptimizacion.MINIMIZAR;
	private TipoDeSolucion tipoDeSolucion = TipoDeSolucion.LISTA;

	public ProblemaAbstracto() {
	}

	public ProblemaAbstracto(Datos d) {
		this();

		datos = d;

		if (d instanceof DatosDiscretos) {
			datosDiscretos = (DatosDiscretos) datos;
		}

	}

	public TipoDeObjetivo getTipoDeObjetivo() {
		return tipoDeObjetivo;
	}

	public void setTipoDeObjetivo(TipoDeObjetivo o) {
		tipoDeObjetivo = o;
	}

	public TipoDeOptimizacion getTipoDeOptimizacion() {
		return tipoDeOptimizacion;
	}

	public void setTipoDeOptimizacion(TipoDeOptimizacion t) {
		tipoDeOptimizacion = t;
	}

	public void setTipoDeSolucion(TipoDeSolucion t) {
		tipoDeSolucion = t;
	}

	public TipoDeSolucion getTipoDeSolucion() {
		return tipoDeSolucion;
	}

	public Datos getDatos() {
		return datos;
	}

	public DatosDiscretos getDatosDiscretos() {
		return datosDiscretos;
	}

	public boolean esSolucion(Solucion s) {
		boolean res = false;
		if (s != null) {
			switch (tipoDeSolucion) {
			case LISTA:
				SolucionLista sol = (SolucionLista) s;
				boolean a1 = true,
				a2 = true,
				a3 = true,
				a4 = true;

				if (!sol.isEmpty()) {
					List<Elemento> camino = sol.getLista();

					if (datosDiscretos.hayNodosIniciales()) {
						a1 = datosDiscretos.getNodosIniciales().contains(
								sol.getPrimero());
					}
					if (datosDiscretos.hayNodosFinales()) {
						a2 = datosDiscretos.getNodosFinales().contains(
								sol.getUltimo());
					}
					List<Elemento> subcamino = camino.subList(1, camino.size());
					Vertice e0 = (Vertice) sol.getPrimero();
					for (Elemento e : subcamino) {
						if (e0.hayVecinos()) {
							a4 = a4 && e0.getVecinos().contains(e);
							e0 = (Vertice) e;
						}
					}
					res = a1 && a2 && a3 && a4;
				}
				break;

			case CONJUNTO:
				res = true;
				break;
			case MULTICONJUNTO:
				SolucionConjunto s1 = (SolucionConjunto) s;
				ElementoConVariasInstancias e1 = null;
				res = true;
				for (Elemento e : s1.getConjunto()) {
					if (e instanceof ElementoConVariasInstancias) {
						e1 = (ElementoConVariasInstancias) e;
						res = e1.getNumInstancias() <= e1.getNumMaxInstancias();
					}
					if (!res)
						break;
				}
			}
		}
		return res;
	}

}
